/*
 * A TimerEnhance for React Native app (es6) which replaced TimerMixin (es5)
 * provides timer functions for executing code in the future that are safely cleaned up when the component unmounts
 * https://github.com/react-native-component/react-native-smart-timer-enhance/
 * Released under the MIT license
 * Copyright (c) 2016 react-native-component <moonsunfall@aliyun.com>
 */

let TimerEnhance = (ComposedComponent) => {

    let setter = (_setter, _clearer, _key) => {
        return function (callback, interval) {
            let timerId = _setter((...params) => {
                _clearer.call(this, timerId)
                callback.apply(this, params)
            }, interval)
            let { [_key]: timers } = this
            if (!timers) {
                this[ _key ] = [ timerId ]
            } else {
                timers.push(timerId)
            }
            return timerId
        }
    }

    let clearer = (_clearer, _key) => {
        return function (timerId) {
            let { [_key]: timers } = this
            if (timers) {
                let index = timers.indexOf(timerId)
                if (~index) {
                    timers.splice(index, 1)
                }
            }
            _clearer(timerId)
        }
    }

    let _timeouts = 'TimerEnhance_timeouts'
    let _clearTimeout = clearer(clearTimeout, _timeouts)
    let _setTimeout = setter(setTimeout, _clearTimeout, _timeouts)

    let _intervals = 'TimerEnhance_intervals'
    let _clearInterval = clearer(clearInterval, _intervals)
    let _setInterval = setter(setInterval, () => {}, _intervals)

    let _immediates = 'TimerEnhance_immediates'
    let _clearImmediate = clearer(clearImmediate, _immediates)
    let _setImmediate = setter(setImmediate, _clearImmediate, _immediates)

    let _animationFrames = 'TimerEnhance_animationFrames'
    let _cancelAnimationFrame = clearer(cancelAnimationFrame, _animationFrames)
    let _requestAnimationFrame = setter(requestAnimationFrame, _cancelAnimationFrame, _animationFrames)

    return class extends ComposedComponent {

        componentWillUnmount () {
            super.componentWillUnmount && super.componentWillUnmount()
            let {
                [_timeouts]: timeouts,
                [_intervals]: intervals,
                [_immediates]: immediates,
                [_animationFrames]: animationFrames,
                } = this
            timeouts && timeouts.forEach((timerId) => {
                clearTimeout(timerId)
            })
            this[ _timeouts ] = null
            intervals && intervals.forEach((timerId) => {
                clearInterval(timerId)
            })
            this[ _intervals ] = null
            immediates && immediates.forEach((timerId) => {
                clearImmediate(timerId)
            })
            this[ _immediates ] = null
            animationFrames && animationFrames.forEach((timerId) => {
                cancelAnimationFrame(timerId)
            })
            this[ _animationFrames ] = null
        }

        setTimeout = _setTimeout
        clearTimeout = _clearTimeout

        setInterval = _setInterval
        clearInterval = _clearInterval

        setImmediate = _setImmediate
        clearImmediate = _clearImmediate

        requestAnimationFrame = _requestAnimationFrame
        cancelAnimationFrame = _cancelAnimationFrame

    }
}
export default TimerEnhance




